/**
 * Echarts组件封装。
 * 该组件使用React Hooks和Echarts库结合，用于在React应用中渲染Echarts图表。
 * 
 * @param {Object} props - 组件的属性。
 * @param {Object} props.option - Echarts图表的配置选项。该选项用于初始化和更新图表。
 *                              如果未提供，则图表将不会被初始化。
 */
import { ForwardedRef, ReactElement, useEffect, useRef } from 'react'
import * as echarts from 'echarts';
import './index.scss'
import { ECElementEvent, EChartsCoreOption, EChartsType } from 'echarts';
import { Spin } from 'antd';
export type Prop = {
  option:  EChartsCoreOption,
  width: number | string;
  height: number | string;
  merge?: boolean;
  loading?: boolean;
  empty?: ReactElement;
  onClick?(event: ECElementEvent): any;
}
export type MyChartRef = {
  instance(): EChartsType | undefined;
}
const Echarts = memo(forwardRef((props: Prop, ref: ForwardedRef<MyChartRef>) => {
  const { option, width, height, loading = false, onClick } = props
  // 使用useRef钩子来存储图表容器的DOM元素引用。
  const box = useRef<HTMLDivElement>(null);
  const cInstance = useRef<EChartsType>();

  // 初始化注册组件，监听 cRef 和 option 变化
  useEffect(() => {
    if (box.current) {
      // 校验 Dom 节点上是否已经挂载了 ECharts 实例，只有未挂载时才初始化
      cInstance.current = echarts.getInstanceByDom(box.current);
      if (!cInstance.current) {
        cInstance.current = echarts.init(box.current, undefined, {
          renderer: 'svg',
        });

        cInstance.current.on('click', (event) => {
          const ec = event as ECElementEvent;
          if (ec && onClick) onClick(ec);
        });
      }

      // 设置配置项
      if (option) cInstance.current?.setOption(option);
    }
  }, [box, option]);

  // 监听窗口大小变化重绘
  useEffect(() => {
    window.addEventListener('resize', resize);
    return () => {
      window.removeEventListener('resize', resize);
    };
  }, [option]);

  // 监听高度变化
  useLayoutEffect(() => {
    resize();
  }, [width, height]);

  // 重新适配大小并开启过渡动画
  const resize = () => {
    cInstance.current?.resize({
      animation: { duration: 300 }
    });
  }

  // 获取实例
  const instance = () => {
    return cInstance.current;
  }

  // 对父组件暴露的方法
  useImperativeHandle(ref, () => ({
    instance
  }));

  // 返回图表的容器元素。
  return (
    <Spin spinning={loading}>
      <div ref={box} style={{ width: width, height: height }} />
    </Spin>
  )
}))

export default Echarts